/*!
 * # Semantic UI 2.0.0 - Video
 * http://github.com/semantic-org/semantic-ui/
 *
 *
 * Copyright 2014 Contributors
 * Released under the MIT license
 * http://opensource.org/licenses/MIT
 *
 */

;(function ($, window, document, undefined) {

    "use strict";

    $.fn.video = function (parameters) {

        var
            $allModules = $(this),

            moduleSelector = $allModules.selector || '',

            time = new Date().getTime(),
            performance = [],

            query = arguments[0],
            methodInvoked = (typeof query == 'string'),
            queryArguments = [].slice.call(arguments, 1),

            requestAnimationFrame = window.requestAnimationFrame
                || window.mozRequestAnimationFrame
                || window.webkitRequestAnimationFrame
                || window.msRequestAnimationFrame
                || function (callback) {
                    setTimeout(callback, 0);
                },

            returnedValue
        ;

        $allModules
            .each(function () {
                var
                    settings = ($.isPlainObject(parameters))
                        ? $.extend(true, {}, $.fn.video.settings, parameters)
                        : $.extend({}, $.fn.video.settings),

                    selector = settings.selector,
                    className = settings.className,
                    error = settings.error,
                    metadata = settings.metadata,
                    namespace = settings.namespace,
                    templates = settings.templates,

                    eventNamespace = '.' + namespace,
                    moduleNamespace = 'module-' + namespace,

                    $window = $(window),
                    $module = $(this),
                    $placeholder = $module.find(selector.placeholder),
                    $playButton = $module.find(selector.playButton),
                    $embed = $module.find(selector.embed),

                    element = this,
                    instance = $module.data(moduleNamespace),
                    module
                ;

                module = {

                    initialize: function () {
                        module.debug('Initializing video');
                        module.create();
                        $module
                            .on('click' + eventNamespace, selector.placeholder, module.play)
                            .on('click' + eventNamespace, selector.playButton, module.play)
                        ;
                        module.instantiate();
                    },

                    instantiate: function () {
                        module.verbose('Storing instance of module', module);
                        instance = module;
                        $module
                            .data(moduleNamespace, module)
                        ;
                    },

                    create: function () {
                        var
                            image = $module.data(metadata.image),
                            html = templates.video(image)
                        ;
                        $module.html(html);
                        module.refresh();
                        if (!image) {
                            module.play();
                        }
                        module.debug('Creating html for video element', html);
                    },

                    destroy: function () {
                        module.verbose('Destroying previous instance of video');
                        module.reset();
                        $module
                            .removeData(moduleNamespace)
                            .off(eventNamespace)
                        ;
                    },

                    refresh: function () {
                        module.verbose('Refreshing selector cache');
                        $placeholder = $module.find(selector.placeholder);
                        $playButton = $module.find(selector.playButton);
                        $embed = $module.find(selector.embed);
                    },

                    // sets new video
                    change: function (source, id, url) {
                        module.debug('Changing video to ', source, id, url);
                        $module
                            .data(metadata.source, source)
                            .data(metadata.id, id)
                            .data(metadata.url, url)
                        ;
                        settings.onChange();
                    },

                    // clears video embed
                    reset: function () {
                        module.debug('Clearing video embed and showing placeholder');
                        $module
                            .removeClass(className.active)
                        ;
                        $embed
                            .html(' ')
                        ;
                        $placeholder
                            .show()
                        ;
                        settings.onReset();
                    },

                    // plays current video
                    play: function () {
                        module.debug('Playing video');
                        var
                            source = $module.data(metadata.source) || false,
                            url = $module.data(metadata.url) || false,
                            id = $module.data(metadata.id) || false
                        ;
                        $embed
                            .html(module.generate.html(source, id, url))
                        ;
                        $module
                            .addClass(className.active)
                        ;
                        settings.onPlay();
                    },

                    get: {
                        source: function (url) {
                            if (typeof url !== 'string') {
                                return false;
                            }
                            if (url.search('youtube.com') !== -1) {
                                return 'youtube';
                            }
                            else if (url.search('vimeo.com') !== -1) {
                                return 'vimeo';
                            }
                            return false;
                        },
                        id: function (url) {
                            if (url.match(settings.regExp.youtube)) {
                                return url.match(settings.regExp.youtube)[1];
                            }
                            else if (url.match(settings.regExp.vimeo)) {
                                return url.match(settings.regExp.vimeo)[2];
                            }
                            return false;
                        }
                    },

                    generate: {
                        // generates iframe html
                        html: function (source, id, url) {
                            module.debug('Generating embed html');
                            var
                                html
                            ;
                            // allow override of settings
                            source = source || settings.source;
                            id = id || settings.id;
                            if ((source && id) || url) {
                                if (!source || !id) {
                                    source = module.get.source(url);
                                    id = module.get.id(url);
                                }
                                if (source == 'vimeo') {
                                    html = ''
                                        + '<iframe src="//player.vimeo.com/video/' + id + '?=' + module.generate.url(source) + '"'
                                        + ' width="100%" height="100%"'
                                        + ' frameborder="0" webkitAllowFullScreen mozallowfullscreen allowFullScreen></iframe>'
                                    ;
                                }
                                else if (source == 'youtube') {
                                    html = ''
                                        + '<iframe src="//www.youtube.com/embed/' + id + '?=' + module.generate.url(source) + '"'
                                        + ' width="100%" height="100%"'
                                        + ' frameborder="0" webkitAllowFullScreen mozallowfullscreen allowFullScreen></iframe>'
                                    ;
                                }
                            }
                            else {
                                module.error(error.noVideo);
                            }
                            return html;
                        },

                        // generate url parameters
                        url: function (source) {
                            var
                                api = (settings.api)
                                    ? 1
                                    : 0,
                                autoplay = (settings.autoplay === 'auto')
                                    ? ($module.data('image') !== undefined)
                                    : settings.autoplay,
                                hd = (settings.hd)
                                    ? 1
                                    : 0,
                                showUI = (settings.showUI)
                                    ? 1
                                    : 0,
                                // opposite used for some params
                                hideUI = !(settings.showUI)
                                    ? 1
                                    : 0,
                                url = ''
                            ;
                            if (source == 'vimeo') {
                                url = ''
                                    + 'api=' + api
                                    + '&amp;title=' + showUI
                                    + '&amp;byline=' + showUI
                                    + '&amp;portrait=' + showUI
                                    + '&amp;autoplay=' + autoplay
                                ;
                                if (settings.color) {
                                    url += '&amp;color=' + settings.color;
                                }
                            }
                            if (source == 'ustream') {
                                url = ''
                                    + 'autoplay=' + autoplay
                                ;
                                if (settings.color) {
                                    url += '&amp;color=' + settings.color;
                                }
                            }
                            else if (source == 'youtube') {
                                url = ''
                                    + 'enablejsapi=' + api
                                    + '&amp;autoplay=' + autoplay
                                    + '&amp;autohide=' + hideUI
                                    + '&amp;hq=' + hd
                                    + '&amp;modestbranding=1'
                                ;
                                if (settings.color) {
                                    url += '&amp;color=' + settings.color;
                                }
                            }
                            return url;
                        }
                    },

                    setting: function (name, value) {
                        module.debug('Changing setting', name, value);
                        if ($.isPlainObject(name)) {
                            $.extend(true, settings, name);
                        }
                        else if (value !== undefined) {
                            settings[name] = value;
                        }
                        else {
                            return settings[name];
                        }
                    },
                    internal: function (name, value) {
                        if ($.isPlainObject(name)) {
                            $.extend(true, module, name);
                        }
                        else if (value !== undefined) {
                            module[name] = value;
                        }
                        else {
                            return module[name];
                        }
                    },
                    debug: function () {
                        if (settings.debug) {
                            if (settings.performance) {
                                module.performance.log(arguments);
                            }
                            else {
                                module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':');
                                module.debug.apply(console, arguments);
                            }
                        }
                    },
                    verbose: function () {
                        if (settings.verbose && settings.debug) {
                            if (settings.performance) {
                                module.performance.log(arguments);
                            }
                            else {
                                module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':');
                                module.verbose.apply(console, arguments);
                            }
                        }
                    },
                    error: function () {
                        module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
                        module.error.apply(console, arguments);
                    },
                    performance: {
                        log: function (message) {
                            var
                                currentTime,
                                executionTime,
                                previousTime
                            ;
                            if (settings.performance) {
                                currentTime = new Date().getTime();
                                previousTime = time || currentTime;
                                executionTime = currentTime - previousTime;
                                time = currentTime;
                                performance.push({
                                    'Name': message[0],
                                    'Arguments': [].slice.call(message, 1) || '',
                                    'Element': element,
                                    'Execution Time': executionTime
                                });
                            }
                            clearTimeout(module.performance.timer);
                            module.performance.timer = setTimeout(module.performance.display, 500);
                        },
                        display: function () {
                            var
                                title = settings.name + ':',
                                totalTime = 0
                            ;
                            time = false;
                            clearTimeout(module.performance.timer);
                            $.each(performance, function (index, data) {
                                totalTime += data['Execution Time'];
                            });
                            title += ' ' + totalTime + 'ms';
                            if (moduleSelector) {
                                title += ' \'' + moduleSelector + '\'';
                            }
                            if ($allModules.length > 1) {
                                title += ' ' + '(' + $allModules.length + ')';
                            }
                            if ((console.group !== undefined || console.table !== undefined) && performance.length > 0) {
                                console.groupCollapsed(title);
                                if (console.table) {
                                    console.table(performance);
                                }
                                else {
                                    $.each(performance, function (index, data) {
                                        console.log(data['Name'] + ': ' + data['Execution Time'] + 'ms');
                                    });
                                }
                                console.groupEnd();
                            }
                            performance = [];
                        }
                    },
                    invoke: function (query, passedArguments, context) {
                        var
                            object = instance,
                            maxDepth,
                            found,
                            response
                        ;
                        passedArguments = passedArguments || queryArguments;
                        context = element || context;
                        if (typeof query == 'string' && object !== undefined) {
                            query = query.split(/[\. ]/);
                            maxDepth = query.length - 1;
                            $.each(query, function (depth, value) {
                                var camelCaseValue = (depth != maxDepth)
                                    ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1)
                                    : query
                                ;
                                if ($.isPlainObject(object[camelCaseValue]) && (depth != maxDepth)) {
                                    object = object[camelCaseValue];
                                }
                                else if (object[camelCaseValue] !== undefined) {
                                    found = object[camelCaseValue];
                                    return false;
                                }
                                else if ($.isPlainObject(object[value]) && (depth != maxDepth)) {
                                    object = object[value];
                                }
                                else if (object[value] !== undefined) {
                                    found = object[value];
                                    return false;
                                }
                                else {
                                    module.error(error.method, query);
                                    return false;
                                }
                            });
                        }
                        if ($.isFunction(found)) {
                            response = found.apply(context, passedArguments);
                        }
                        else if (found !== undefined) {
                            response = found;
                        }
                        if ($.isArray(returnedValue)) {
                            returnedValue.push(response);
                        }
                        else if (returnedValue !== undefined) {
                            returnedValue = [returnedValue, response];
                        }
                        else if (response !== undefined) {
                            returnedValue = response;
                        }
                        return found;
                    }
                };

                if (methodInvoked) {
                    if (instance === undefined) {
                        module.initialize();
                    }
                    module.invoke(query);
                }
                else {
                    if (instance !== undefined) {
                        instance.invoke('destroy');
                    }
                    module.initialize();
                }
            })
        ;
        return (returnedValue !== undefined)
            ? returnedValue
            : this
            ;
    };

    $.fn.video.settings = {

        name: 'Video',
        namespace: 'video',

        debug: false,
        verbose: false,
        performance: true,

        metadata: {
            id: 'id',
            image: 'image',
            source: 'source',
            url: 'url'
        },

        source: false,
        url: false,
        id: false,

        aspectRatio: (16 / 9),

        onPlay: function () {
        },
        onReset: function () {
        },
        onChange: function () {
        },

        // callbacks not coded yet (needs to use jsapi)
        onPause: function () {
        },
        onStop: function () {
        },

        width: 'auto',
        height: 'auto',

        autoplay: 'auto',
        color: '#442359',
        hd: true,
        showUI: false,
        api: true,

        regExp: {
            youtube: /^(?:https?:\/\/)?(?:www\.)?(?:youtu\.be\/|youtube\.com\/(?:embed\/|v\/|watch\?v=|watch\?.+&v=))((\w|-){11})(?:\S+)?$/,
            vimeo: /http:\/\/(www\.)?vimeo.com\/(\d+)($|\/)/
        },

        error: {
            noVideo: 'No video specified',
            method: 'The method you called is not defined'
        },

        className: {
            active: 'active'
        },

        selector: {
            embed: '.embed',
            placeholder: '.placeholder',
            playButton: '.play'
        }
    };

    $.fn.video.settings.templates = {
        video: function (image) {
            var
                html = ''
            ;
            if (image) {
                html += ''
                    + '<i class="video play icon"></i>'
                    + '<img class="placeholder" src="' + image + '">'
                ;
            }
            html += '<div class="embed"></div>';
            return html;
        }
    };


})(jQuery, window, document);
